#ifndef _SE_ENTITY_
#define _SE_ENTITY_

#include "Scene/Scene.h"

#include "Scene/Components.h"

namespace SE
{
	class Entity final
	{
	private:
		Scene* mScene;
		entt::entity mNativeEntity;

	public:
		Entity();
		Entity(Scene* scene, const entt::entity nativeEntity);
		~Entity() = default;

		template<typename _Ty, typename... Args>
		_Ty& addComponent(Args&&... args)
		{
			SE_ASSERT(!hasComponent<_Ty>(), "Entity already has component!");
			_Ty& component = mScene->mRegistry.emplace<_Ty>(mNativeEntity, std::forward<Args>(args)...);
			return component;
		}

		template<typename _Ty, typename... Args>
		_Ty& addOrReplaceComponent(Args&&... args)
		{
			_Ty& component = mScene->mRegistry.emplace_or_replace<_Ty>(mNativeEntity, std::forward<Args>(args)...);
			return component;
		}

		template<typename _Ty>
		_Ty& getComponent()
		{
			SE_ASSERT(hasComponent<_Ty>(), "Entity does not have component!");
			return mScene->mRegistry.get<_Ty>(mNativeEntity);
		}

		template<typename... _Tys>
		Boolean hasComponent()
		{
			return mScene->mRegistry.all_of<_Tys...>(mNativeEntity);
		}

		template<typename _Ty>
		void removeComponent()
		{
			SE_ASSERT(hasComponent<_Ty>(), "Entity does not have component!");
			mScene->mRegistry.remove<_Ty>(mNativeEntity);
		}

		operator Boolean() const { return mNativeEntity != entt::null; }
		operator entt::entity() const { return mNativeEntity; }
		operator U32() const { return (U32)mNativeEntity; }

		const String& getName() { return getComponent<TagComponent>().tag; }

		Boolean operator==(const Entity& other) const
		{
			return mNativeEntity == other.mNativeEntity && mScene == other.mScene;
		}

		Boolean operator!=(const Entity& other) const
		{
			return !(*this == other);
		}
	};
} // !namespace SE

#endif // !_SE_ENTITY_